package la.iok.hzsvn.lewin.movie.operation.service;

import la.iok.hzsvn.lewin.movie.core.Token;
import la.iok.hzsvn.lewin.movie.core.model.PlayRecordVo;
import la.iok.hzsvn.lewin.movie.operation.entity.FinancialAccount;
import la.iok.hzsvn.lewin.movie.operation.entity.PlayRecord;
import la.iok.hzsvn.lewin.movie.operation.model.EndParam;
import la.iok.hzsvn.lewin.movie.operation.model.PlayRecordAutoEndCfg;
import la.iok.hzsvn.lewin.movie.operation.model.PlayRecordParam;
import la.iok.hzsvn.lewin.movie.operation.model.PreviewLuckyMoney;
import la.iok.hzsvn.lewin.mybatis.model.PageVo;
import la.iok.hzsvn.lewin.mybatis.service.BaseService;
import la.iok.hzsvn.share.annotations.NotNull;
import la.iok.hzsvn.share.annotations.NotNullElement;
import la.iok.hzsvn.share.annotations.Nullable;

import java.util.Collection;
import java.util.Date;
import java.util.List;

public interface PlayRecordService extends BaseService<PlayRecord,Long> {
    /**
     * 开本。创建一个新的记录
     * @param token 开本设备令牌
     * @param param 开本参数
     * @return 新增记录id
     */
    Long start(@NotNull Token token, @NotNull PlayRecordParam param);

    /**
     * 结束播放。同一时间,同一设备只能有一个在播放的剧本。播放另外的剧本之前需要先关闭正在播放的剧本
     * @param token 操作用户或者设备
     * @param param 结束参数
     */
    void end(@NotNull Token token, @Nullable EndParam param);

    /**
     * 系统自动结束未结束但是应该结束的开本记录
     */
    int endBySystem();

    /**
     * 查询播放中的播放记录，包括正在结束的播放记录.
     * @param token 设备或者dm
     * @return 播放记录。如果是设备,返回设备关联的所有播放中和正在结束的播放记录。如果是DM,则返回DM在当前组织所有播放中和正在结束的播放记录
     */
    @NotNull
    @NotNullElement
    List<PlayRecord> playingRecords(@NotNull Token token);

    /**
     * 查询当前需要结束的开本记录。根据配置，当剧本的开本时间加上配置的剧本时长及系统配置的额外时间之后，已经小于当前时间,那就应该要被系统给自动结束掉。
     * @return 需要结束的记录
     */
    List<PlayRecord> need2End();

    /**
     * 房间中正在进行的开本记录
     * @param roomId 房间id
     * @return 房间进行中的开本记录列表，一般只有一个
     */
    @NotNull
    @NotNullElement
    List<PlayRecord> roomPlayingRecords(@Nullable Long roomId);

    @NotNull
    @NotNullElement
    List<PlayRecordVo> po2vo(@Nullable @NotNullElement List<PlayRecord> playRecords);
    @Nullable
    PlayRecordVo po2vo(@Nullable PlayRecord playRecord);

    PageVo<PlayRecordVo> page(Token token, int page, int limit, String orderColumn, String order, Long orgUnitId, Long userId);
    PageVo<PlayRecordVo> page(Token token, int page, int limit, String orderColumn, String order, String name, Long orgUnitId, Long roomId, Long userId, Date start, Date end);

    /**
     * 重新进入剧本播放。针对可能出现的异常情况,能够让客户端重新进入并继续播放
     * @param token 重新进入的设备令牌，必须是设备的令牌，以便可以播放
     * @param id 播放记录id,必须存在并且是播放中状态
     * @return 播放记录vo对象
     */
    @NotNull
    PlayRecordVo enter(@NotNull Token token, @Nullable Long id);

    /**
     * 统计总金额
     * @param token 操作用户
     * @param start 开始时间
     * @param end 结束时间
     * @return 总金额
     */
    int total(@NotNull Token token, @NotNull Date start, @NotNull Date end);

    /**
     * 计算房间总的开本数量，需要排除测试开本的记录
     * @param start 统计的开始时间
     * @param end 统计的结束时间
     * @param roomId 房间id
     * @param excludeMovieIds 需要排除的剧本id集合。有些剧本不参与返利计算
     * @return 统计的数量
     */
    int totalPlays(@NotNull Date start, @NotNull Date end,@Nullable Long roomId, @Nullable @NotNullElement Collection<Long> excludeMovieIds);

    /**
     * 统计房间消费总金额
     * @param start 统计的开始时间
     * @param end 统计的结束时间
     * @param roomId 房间id
     * @param excludeMovieIds 需要排除的剧本id集合。有些剧本不参与返利计算
     * @return 统计的总金额
     */
    int totalCost(@NotNull Date start, @NotNull Date end,@Nullable Long roomId, @Nullable @NotNullElement Collection<Long> excludeMovieIds);

    /**
     * 计算返利
     * @param excludes 需要排除的金融账号的id
     * @param success 成功发放返利的金融账号id
     * @param lessAmount 开本次数不达标的金融账号的id
     * @param start 统计开始时间
     * @param end 统计结束时间
     * @param excludeMovieIds 需要排除的剧本id集合。有些剧本不参与返利计算
     * @param supportReturnMoneyRoomIds 支持返利计算的房间
     * @return 当前处理的金融账号,如果返回null则表示所有账号已经处理完成
     */
    @Nullable
    FinancialAccount processReturnMoney(@NotNull @NotNullElement Collection<Long> excludes, @NotNull @NotNullElement Collection<Long> success,
                                        @NotNull @NotNullElement Collection<Long> lessAmount, @NotNull Date start, @NotNull Date end,
                                        @Nullable @NotNullElement Collection<Long> excludeMovieIds, @NotNull @NotNullElement Collection<Long> supportReturnMoneyRoomIds);

    void processReturnMoney(@NotNull @NotNullElement Collection<Long> excludes, @NotNull @NotNullElement Collection<Long> success,
                       @NotNull @NotNullElement Collection<Long> lessAmount);

    /**
     * 预览当前月份已经产生的数据的返利情况
     * @param token 操作用户。只有超级管理员才能调用
     * @return 返利数据预览
     */
    PreviewLuckyMoney previewReturnMoney(@NotNull Token token);

    /**
     * 查询剧本的开本记录数
     * @param movieId 剧本id
     * @param version 剧本版本
     * @return 开本次数
     */
    Integer count(Long movieId, String version);

    /**
     * 查询开本记录的剩余时间
     * @param token 操作用户
     * @param id 开本记录id
     * @return 剩余时间,单位秒
     */
    Integer remainingTime(@NotNull Token token, @Nullable Long id);

    PlayRecordAutoEndCfg cfg();
}
